import "./text-overflow.less";
import { createPopper } from "@popperjs/core";

function handleInserted(el, binding) {
  handleOverflow(el, binding);
}

function handleUpdate(el, binding) {
  tryRemoveOldPopper();
  handleOverflow(el, binding);
}

function handleOverflow(el, binding) {
  if (el.mouseenterController) {
    el.mouseenterController.abort();
  }
  if (el.mouseleaveController) {
    el.mouseleaveController.abort();
  }

  const config = {
    width: binding.value?.width || 0,
    maxWidth: binding.value?.maxWidth || 0,
    placement: binding.value?.placement || "top",
    ellipsis:
      binding.value?.ellipsis !== undefined ? binding.value.ellipsis : true,
    tipWidth: binding.value?.tipWidth || 500,
    isBlock:
      binding.value?.isBlock !== undefined ? binding.value.isBlock : false,
    innerText: el.innerText,
  };

  el.style.overflow = "hidden";
  el.style["white-space"] = "nowrap";

  if (config.isBlock) {
    el.style.display = "block";
  } else {
    el.style.display = "inline-block";
  }

  if (config.ellipsis) {
    el.style["text-overflow"] = "ellipsis";
  }

  if (config.width) {
    el.style.width = `${config.width}px`;
  }

  if (config.maxWidth) {
    el.style["max-width"] = `${config.maxWidth}px`;
  }

  const div = document.createElement("div");
  div.setAttribute("id", "ga-popover");
  div.classList.add("ga-popover");
  div.setAttribute("placement", config.placement);
  div.style["max-width"] = `${config.tipWidth}px`;
  const arrowChild = document.createElement("div");
  arrowChild.classList.add("arrow");
  div.appendChild(arrowChild);
  const spanChild = document.createElement("span");
  spanChild.innerText = config.innerText;
  div.appendChild(spanChild);

  el.mouseenterController = new AbortController();
  el.mouseleaveController = new AbortController();
  el.addEventListener(
    "mouseenter",
    () => {
      if (isTextOverflow(el)) {
        document.body.appendChild(div);
        createPopper(el, div, {
          placement: config.placement,
        });
      }
    },
    { signal: el.mouseenterController.signal }
  );

  el.addEventListener(
    "mouseleave",
    () => {
      if (isTextOverflow(el)) {
        document.body.removeChild(div);
      }
    },
    { signal: el.mouseleaveController.signal }
  );
}

function handleUnbind(el) {
  el.mouseenterController.abort();
  el.mouseleaveController.abort();
  tryRemoveOldPopper();
}

function tryRemoveOldPopper() {
  const div = document.getElementById("ga-popover");

  if (div) {
    document.removeChild(div);
  }
}

function isTextOverflow(el) {
  // 判断是否text-overflow
  const range = document.createRange();
  range.setStart(el, 0);
  range.setEnd(el, el.childNodes.length);
  const rangeWidth = range.getBoundingClientRect().width;
  const padding =
    (parseInt(el.style.paddingLeft, 10) || 0) +
    (parseInt(el.style.paddingRight, 10) || 0);
  if (
    rangeWidth + padding > el.offsetWidth ||
    el.scrollWidth > el.offsetWidth
  ) {
    return true;
  }
  return false;
}

export function useTextOverflow(Vue) {
  Vue.directive("text-overflow", {
    inserted: handleInserted,
    update: handleUpdate,
    unbind: handleUnbind,
  });
}
